package org.enhance.dxf.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;

import org.apache.commons.lang3.StringUtils;
import org.enhance.common.exception.InternalAssertionException;
import org.enhance.common.util.Assertion;
import org.enhance.common.util.Detect;

import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.MultiTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.ext.beans.BeansWrapperBuilder;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class FreemarkerSupport {

	private Configuration configuration;

	private FreemarkerSupport() {
		configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);

		ClassTemplateLoader classTemplateLoader = new ClassTemplateLoader(ClassTemplateLoader.class, "/");
		TemplateLoader[] loaders = new TemplateLoader[] { classTemplateLoader };

		configuration.setTemplateLoader(new MultiTemplateLoader(loaders));
		configuration.setObjectWrapper(new BeansWrapperBuilder(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS).build());
	}

	private static class SingletonHelper {
		private static FreemarkerSupport instance = new FreemarkerSupport();
	}

	public static FreemarkerSupport getInstance() {
		return SingletonHelper.instance;
	}

	public String processPath(String templatePath, Object object) {
		return processPath(templatePath, object, false);
	}

	private String processPath(String templatePath, Object object, boolean removeBlankLines) {
		Template template;
		try {
			template = configuration.getTemplate(templatePath);
		} catch (IOException e) {
			log.error(e.getMessage(), e);
			throw new InternalAssertionException("failed to get template by (templatePath=" + templatePath + ")", e);
		}
		String templateStr = this.processTemplate(template, object);
		if (removeBlankLines) {
			templateStr = removeBlankLines(templateStr);
		}
		return templateStr;
	}

	private String processTemplate(Template template, Object object) {
		StringWriter writer = new StringWriter();
		try {
			Assertion.notNull(template, "Template not found.");
			template.process(object, writer);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new InternalAssertionException("failed to get template by (template=" + template + ")", e);
		}
		return writer.toString();
	}

	private String removeBlankLines(String src) {
		if (Detect.notEmpty(src)) {
			StringBuilder sb = new StringBuilder();
			String inputLine;
			String lineSepartor = System.getProperty("line.separator");
			try (BufferedReader bufferedReader = new BufferedReader(new StringReader(src))) {
				while ((inputLine = bufferedReader.readLine()) != null) {
					if (inputLine.length() == 0 || StringUtils.isWhitespace(inputLine)) {
						continue;
					}
					sb.append(inputLine).append(lineSepartor);
				}
			} catch (IOException e) {
				log.error(e.getMessage(), e);
				throw new InternalAssertionException("failed to read source string (src=" + src + ")", e);
			}
			return sb.toString();
		}
		return src;
	}
}
